package com.gowants.pems.util;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
import java.util.UUID;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.gowants.pems.mapper.SysLogMapper;
import com.gowants.pems.model.SysLog;

@Component
public class TcpServerNew {

	@Autowired
	private SysLogMapper logMapper;

	private static SysLogMapper service;

	public @PostConstruct void init() {
		service = logMapper;
	}

	private int ii = 0;
	/* 标识数字 */
	private int flag = 0;
	/* 缓冲区大小 */
	private int BLOCK = 40960;
	/* 接受数据缓冲区 */
	private ByteBuffer sendbuffer = ByteBuffer.allocate(BLOCK);
	/* 发送数据缓冲区 */
	private ByteBuffer receivebuffer = ByteBuffer.allocate(BLOCK);
	private Selector selector;

	public void NIOServer(int port) {
		try {
			// 打开服务器套接字通道
			ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
			// 服务器配置为非阻塞
			serverSocketChannel.configureBlocking(false);
			// 检索与此通道关联的服务器套接字
			ServerSocket serverSocket = serverSocketChannel.socket();
			/* 本机IP */
			// InetAddress ip = InetAddress.getByName("127.0.0.1");
			InetAddress ip = InetAddress.getLocalHost();
			/* 绑定IP和端口 */
			InetSocketAddress address = new InetSocketAddress(ip, port);
			// 进行服务的绑定
			serverSocket.bind(address);
			// 通过open()方法找到Selector
			selector = Selector.open();
			// 注册到selector，等待连接
			serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
			System.out.println("TCP服务器开始监听..." + address.toString());
			run();
		} catch (Exception e) {
			// e.printStackTrace();
			SysLog record = new SysLog();
			record.setCreateTime(DateUtil.getDate());
			record.setRemarks("tcp异常:" + e.getMessage());
			record.setType(3);
			record.setImportance(2);
			record.setName("tcp异常记录");
			record.setId(UUID.randomUUID().toString());
			service.save(record);
		}
	}

	// 监听
	public void run() {
		try {
			while (true) {
				// 选择一组键，并且相应的通道已经打开
				selector.select();
				// 返回此选择器的已选择键集。
				Set<SelectionKey> selectionKeys = selector.selectedKeys();
				Iterator<SelectionKey> iterator = selectionKeys.iterator();
				while (iterator.hasNext()) {
					SelectionKey selectionKey = iterator.next();
					iterator.remove();
					try {
						handleKey(selectionKey);

					} catch (IOException e) {
						SocketChannel client = (SocketChannel) selectionKey.channel();
						SocketAddress clientaddr = client.socket().getRemoteSocketAddress();
						SysLog record = new SysLog();
						record.setCreateTime(DateUtil.getDate());
						record.setRemarks("tcp异常:" + clientaddr + "," + e.getMessage());
						record.setType(3);
						record.setImportance(2);
						record.setName("tcp异常记录");
						record.setId(UUID.randomUUID().toString());
						service.save(record);
						// TODO Auto-generated catch block
						// e.printStackTrace();
						selectionKey.cancel(); // 取消selectionKey
						// break;
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	// 处理请求
	private void handleKey(SelectionKey selectionKey) throws IOException {
		// 接受请求
		ServerSocketChannel server = null;
		SocketChannel client = null;
		SocketAddress clientaddr = null;
		String receiveText;
		String sendText;
		int count = 0;

		// 测试此键的通道是否已准备好接受新的套接字连接。

		if (selectionKey.isAcceptable()) {
			// 返回为之创建此键的通道。
			server = (ServerSocketChannel) selectionKey.channel();
			// 接受到此通道套接字的连接。
			// 此方法返回的套接字通道（如果有）将处于阻塞模式。
			client = server.accept();
			clientaddr = client.socket().getRemoteSocketAddress();
			System.out.printf("+++++++++++服务器端接受客户端[%s]连接!+++++++++++ \n", clientaddr);
			// 配置为非阻塞
			client.configureBlocking(false);
			// 注册到selector，等待连接
			client.register(selector, SelectionKey.OP_READ);
			SysLog record = new SysLog();
			record.setCreateTime(DateUtil.getDate());
			record.setRemarks("新终端已连接:" + clientaddr);
			record.setType(3);
			record.setImportance(2);
			record.setId(UUID.randomUUID().toString());
			record.setName("tcp接收数据时新终端连接");
			service.save(record);
			
			client.write(ByteBuffer.wrap(("已连接:"+clientaddr.toString()).getBytes("utf-8")));
			// System.out.println("新终端已连接:"+ clientaddr);

		} else if (selectionKey.isReadable()) {

			try {
				// 返回为之创建此键的通道。
				client = (SocketChannel) selectionKey.channel();
				clientaddr = client.socket().getRemoteSocketAddress();
				// 将缓冲区清空以备下次读取
				receivebuffer.clear();
				// 读取服务器发送来的数据到缓冲区中
				count = client.read(receivebuffer);
				if (count > 0) {
					byte[] arr = receivebuffer.array();
					receiveText = TcpUtil.byteArray2HexString(arr, count, false);
//					System.out.println("接收数据：" + receiveText);
					// 接收到的数据存入缓存

					if (ii == 0) {
						rundata();
						ii = 1;
					}
//					client.write(ByteBuffer.wrap(("已连接:"+clientaddr.toString()+receiveText).getBytes("utf-8")));
					// receiveText = new String( receivebuffer.array(),0,count);
					System.out.printf("服务器端接受客户端[%s]数据:\n%s", clientaddr, receiveText);
					client.register(selector, SelectionKey.OP_WRITE);
				} else {
					client = (SocketChannel) selectionKey.channel();
					clientaddr = client.socket().getRemoteSocketAddress();
					System.out.println("断开连接:" + clientaddr);
					SysLog record = new SysLog();
					record.setCreateTime(DateUtil.getDate());
					record.setRemarks("断开连接:" + clientaddr);
					record.setType(3);
					record.setImportance(2);
					record.setId(UUID.randomUUID().toString());
					record.setName("tcp接收数据时断开连接");
					service.save(record);
					selectionKey.cancel(); // 取消selectionKey

				}
			} catch (IOException e) {

				client = (SocketChannel) selectionKey.channel();
				clientaddr = client.socket().getRemoteSocketAddress();
				System.out.println("异常断开连接:" + clientaddr);
				SysLog record = new SysLog();
				record.setCreateTime(DateUtil.getDate());
				record.setRemarks("异常断开连接:" + clientaddr);
				record.setType(3);
				record.setImportance(2);
				record.setId(UUID.randomUUID().toString());
				record.setName("tcp接收数据时断开连接");
				service.save(record);
				// TODO Auto-generated catch block
				e.printStackTrace();
				selectionKey.cancel(); // 取消selectionKey
			}

		} else if (selectionKey.isWritable()) {
			// 将缓冲区清空以备下次写入
			sendbuffer.clear();
			// 返回为之创建此键的通道。
			client = (SocketChannel) selectionKey.channel();
			sendText = "message from server--" + flag++;
			// 向缓冲区中输入数据
			sendbuffer.put(sendText.getBytes());
			// 将缓冲区各标志复位,因为向里面put了数据标志被改变要想从中读取数据发向服务器,就要复位
			sendbuffer.flip();
			// 输出到通道
//			client.write(sendbuffer);
//			System.out.println("服务器端向客户端发送数据--：" + sendText);
			client.register(selector, SelectionKey.OP_READ);
		}
	}

	public void rundata() {
		// 开启线程处理
		new Thread(new Runnable() {
			@Override
			public void run() {
				while (true) {
					try {
						
						

					} catch (Exception e) {
						// logger.warn("处理数据失败");
						e.printStackTrace();
					}
					try {
						Thread.sleep(1000);// 在给定的时间间隔后再检查状态
					} catch (InterruptedException e) {
						e.printStackTrace();
					}

				}

			}
		}).start();

	}

}
